package zen_group.mdl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.Region;

public class XlsWriter
{
/* Usage Example
	public static void
	main(String args[])
	{
		try
		{
			JFileChooser chooser	= new JFileChooser();
			chooser.showSaveDialog(new Interface());

			int line			= 0;
			int partTitleLine	= line++;
        	int	topHeadingsLine	= line++;
        	int headingsLine	= line++;
        	int resultsLine		= line++;

			XlsWriter	writer	= new XlsWriter(chooser.getSelectedFile());
        	writer
				.cellAbsPos(columns[0])
        			.headCell(item.getKey().title())
        				.setRowHeight(30)
        		.rowAbsPos(topHeadingsLine)
    			.cellAbsPos(columns[1])
    				.headCell("REZERVO NAUDINGUMAS")
    			.rowAbsPos(headingsLine)
    			.cellAbsPos(columns[1])
					.headCell("Kiekis")
					.headCell("Ek. nauda")
						.setColumnWidth(80)
					.headCell("Pelnas")
						.setColumnWidth(80)
        		.rowAbsPos(topHeadingsLine)
        		.cellAbsPos(columns[2])
        			.headCell("TRŪKUMAI")
    			.rowAbsPos(headingsLine)
    			.cellAbsPos(columns[2])
    				.headCell("Kiekis")
    				.headCell("Kartai")
				.rowAbsPos(topHeadingsLine)
				.cellAbsPos(columns[3])
					.headCell("GEDIMAI")
				.rowAbsPos(headingsLine)
				.cellAbsPos(columns[3])
					.headCell("Kiekis")
						.setColumnWidth(80)
					.headCell("Kartai")
				.rowAbsPos(resultsLine);
		}
		catch (Exception e)
		{
			System.err.println("XlsWriter got exception: "
					+ e.getClass() + " "
					+ e.getMessage());
		}

		System.exit(0);
	}
*/

	public
	XlsWriter(File destination)
	{
		mFile	= destination;
		initialize();
	}

	/**
	 * Goes to n-th row
	 * @param n
	 * @return
	 */
	public XlsWriter
	rowAbsPos(int n)
	{
		mRowNum	= 0;
		return rowPos(n);
	}

	/**
	 * Goes to n-th row from current row
	 *
	 * @param n
	 * @return this
	 */
	public XlsWriter
	rowPos(int n)
	{
		mRowNum		+= n;
		mRow		= mSheet.getRow(mRowNum);

		if (null == mRow)
			mRow	= mSheet.createRow(mRowNum);

		return this;
	}

	/**
	 * Creates n new rows in current sheet starting from current row
	 * @param n
	 * @return
	 */
	public XlsWriter
	newLine(int n)
	{
		rowPos(n);
		mCellNum	= -1;
		return this;
	}

	/**
	 * Creates one row in current sheet
	 * @return
	 */
	public XlsWriter
	newLine()
	{
		return newLine(1);
	}

	public XlsWriter
	cellAbsPos(int n)
	{
		//mCellNum	= 0;
		//return cellPos(n);
		mCellNum    = (short)(n - 1);
		return this;
	}

	public XlsWriter
	cellPos(int n)
	{
		mCellNum	+= n;
		mCell		= mRow.getCell(mCellNum);

		if (null == mCell)
			mCell	= mRow.createCell(mCellNum);

		return this;
	}

	/**
	 * Skip n cells in current row
	 * @param n
	 * @return
	 */
	public XlsWriter
	skipCells(int n)
	{
		if (n < 1)
			n	= 1;

		for (int i = 0; i < n; i++)
			mCell	= nextCell();

		return this;
	}

	/**
	 * Skip one cell in current row
	 * @return
	 */
	public XlsWriter
	skipCell()
	{
		return skipCells(1);
	}

	/**
	 * Creates head cell with specific style and font
	 * @param header text
	 * @return
	 */
	public XlsWriter
	headCell(String header)
	{
		mCell	= nextCell(mHeadCell);
		mCell.setCellValue(text(header));
		return this;
	}


	/**
	 * Merge cells
	 * @param count Number of cells to merge
	 * @return
	 */
	public XlsWriter
	merge(int count)
	{
        mSheet.addMergedRegion(
                new Region(
                    (short)mRowNum,
                    (short)mCellNum,
                    (short)mRowNum,
                    (short)(mCellNum + count)
                )
            );
        return this;
	}

	/**
	 * Write string into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cell(String data)
	{
		mCell	= nextCell(mTextCell);
		mCell.setCellValue(text(data));
		return this;
	}

	/**
	 * Write integer value into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cell(int data)
	{
		mCell	= nextCell(mIntCell);
		mCell.setCellValue(data);
		return this;
	}

	/**
	 * Write double value into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cell(double data)
	{
		mCell	= nextCell(mFloatCell);
		mCell.setCellValue(data);
		return this;
	}

	/**
	 * Write boolean value into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cell(boolean data)
	{
		mCell	= nextCell(mTextCell);
		mCell.setCellValue(data);
		return this;
	}

	/**
	 * Write date into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cell(Date data)
	{
		mCell	= nextCell(mDateCell);
		mCell.setCellValue(data);
		return this;
	}

	/**
	 * Write formula into current cell
	 * @param data
	 * @return
	 */
	public XlsWriter
	cellFormula(String formula)
	{
		mCell	= nextCell(mIntCell);
		mCell.setCellFormula(formula);
		return this;
	}

	/**
	 * Sets row height
	 * @param height
	 * @return
	 */
	public XlsWriter
	setRowHeight(int height)
	{
		mRow.setHeightInPoints((float)height);
		return this;
	}

	/**
	 * Set column width
	 * @param width
	 * @return
	 */
	public XlsWriter
	setColumnWidth(int width)
	{
		mSheet.setColumnWidth(mCellNum, (short) ((width * 2) / ((double) 1 / 20)));
		return this;
	}

	/**
	 * Marks current cell to be bold
	 * @todo	control current font and toggle
	 * @return
	 */
	public XlsWriter
	bold()
	{
		mIsBold			= 1;
		mCurrentFont	= font(mBoldFont);
		return this;
	}

	/**
	 * Sets name for current sheet
	 * @param name
	 * @return
	 * @throws IllegalArgumentException
	 */
	public XlsWriter
	setSheetName(String name) throws IllegalArgumentException
	{
		mWorkBook.setSheetName(0, name);
		return this;
	}

	/**
	 * Writes changes into file
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public boolean
	write() throws FileNotFoundException, IOException
	{
		FileOutputStream	output = new FileOutputStream(mFile);
		mWorkBook.write(output);
		return true;
	}

	/**
	 * Initialization procedure
	 */
	private void
	initialize()
	{
		// workbook and worksheet
		mWorkBook	= new HSSFWorkbook();
		mSheet		= mWorkBook.createSheet();

		// initialize fonts
		mBoldFont		= mWorkBook.createFont();
		mBoldFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

		mItalicFont		= mWorkBook.createFont();
		mUnderlinedFont	= mWorkBook.createFont();
		mCurrentFont	= mWorkBook.createFont();
		mLastFont		= mCurrentFont;

		// data format
		mDataFormat	= mWorkBook.createDataFormat();

		// cell styles
		mHeadCell	= mWorkBook.createCellStyle();
		mHeadCell.setBorderTop(HSSFCellStyle.BORDER_THIN);
		mHeadCell.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		//mHeadCell.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM);
		//mHeadCell.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		//mHeadCell.setBorderRight(HSSFCellStyle.BORDER_THIN);
		mHeadCell.setFont(mBoldFont);

		mTextCell	= mWorkBook.createCellStyle();
		mIntCell	= mWorkBook.createCellStyle();

		mFloatCell	= mWorkBook.createCellStyle();
		mFloatCell.setDataFormat(mDataFormat.getFormat("#,##0.00"));

		mDateCell	= mWorkBook.createCellStyle();
		mDateCell.setDataFormat(mDataFormat.getFormat("yyyy-MM-dd"));

		// lets start with first row
		rowPos(0);
	}

	/**
	 * Create and return HSSFRichTextString
	 * for String data to be written in the cells
	 * @param text
	 * @return
	 */
	private HSSFRichTextString
	text(String text)
	{
		return new HSSFRichTextString(text);
	}

	/**
	 * Create and return new cell
	 * @return
	 */
	private HSSFCell
	nextCell()
	{
		cellPos(1);
		mCell.getCellStyle().setFont(getCurrentFont());
		return mCell;
	}

	/**
	 * Create and return new cell with specified style
	 * @param cellStyle
	 * @return
	 */
	private HSSFCell
	nextCell(HSSFCellStyle cellStyle)
	{
		cellPos(1);
		mCell.setCellStyle(cellStyle);
		mCell.getCellStyle().setFont(getCurrentFont());
		return mCell;
	}

	private HSSFFont
	getCurrentFont()
	{
		if (mIsBold-- < 1)
			mCurrentFont	= font();

		return mCurrentFont;
	}

	/**
	 * Set new font to be used in cells
	 * @param setFont
	 * @return
	 */
	private HSSFFont
	font(HSSFFont setFont)
	{
		mLastFont		= mCurrentFont;
		mCurrentFont	= setFont;
		return mCurrentFont;
	}

	/**
	 * Restore previously used font
	 * @return
	 */
	private HSSFFont
	font()
	{
		mCurrentFont	= mLastFont;
		return mCurrentFont;
	}

	private 	File			mFile;

	private 	HSSFWorkbook	mWorkBook;
	private 	HSSFSheet		mSheet;
	private 	HSSFRow			mRow;
	private 	HSSFCell		mCell;
	private 	int				mRowNum		= 0;
	private		short			mCellNum	= -1;

	private 	HSSFCellStyle	mHeadCell;
	private 	HSSFCellStyle	mTextCell;
	private 	HSSFCellStyle	mIntCell;
	private 	HSSFCellStyle	mFloatCell;
	private 	HSSFCellStyle	mDateCell;

	private 	HSSFDataFormat	mDataFormat;

	private		HSSFFont		mBoldFont;
	private		HSSFFont		mItalicFont;
	private		HSSFFont		mUnderlinedFont;
	private 	HSSFFont		mCurrentFont;
	private		HSSFFont		mLastFont;

	private		int				mIsBold		= 0;
}
